package com.ktg.mes.unit.sync1;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ktg.common.utils.StringUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

public class Sync1ServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements ISyncService<T> {

    private Field idFile;
    private String idTableFieldName;

    private Field syncField; //同步两个数据库信息判断的字段
    private String syncFieldName; //同步两个数据库信息判断的字段

    private List<String> selectColunmList; //但却能够操作的数据库colunm

    private List<Field> dsFieldList; //但却能够操作的model 的属性

    private List<Field> dsFieldOnlyList; //仅属于当前能够操作的model 的属性

    private T canItem;

    //保存数据，同时保存到外包数据库
    public boolean saveWithOuter(T item) {
        canItem = (T) initCanItem(item);
        if (canItem == null){
            return false;
        }
        boolean flag = false;
        try {
            if (outerService() != null){
                if (idFile.get(canItem) == null){
                    //获取 已经插入的id
                    QueryWrapper<T> queryWrapper = new QueryWrapper<>(canItem);
                    T cs = getOne(queryWrapper);
                    if (cs == null){
                        return false;
                    }
                    idFile.set(item,idFile.get(cs));
                    flag =outerService().save(outerService().initCanItem(item));
                }else {
                    flag = outerService().save(outerService().initCanItem(item));
                }
            }
            if (flag){
                flag = super.save(canItem);
            }

        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return flag;
    }

    //跟新数据，同时更新外包数据库
    public boolean updateByIdWithOuter(T item) {
        canItem = (T) initCanItem(item);
        if (canItem == null){
            return false;
        }
        if (outerService() != null){
            T outTitem = (T)outerService().initCanItem(item);
           boolean flag = true;
           if (outTitem != null){
               flag = outerService().updateById(outTitem);
           }
           if (flag){
               return super.updateById(canItem);
           }else {
               //查询是否已经删除，如果不存在就新增记录
               QueryWrapper<T> queryWrapper2 = new QueryWrapper<>();
               queryWrapper2.select(idTableFieldName);
               try {
                   queryWrapper2.eq(idTableFieldName,idFile.get(item));
               }catch (Exception e){
                   e.printStackTrace();
               }
               T t = (T) outerService().getOne(queryWrapper2);
               if (t == null){
                   flag = outerService().save(outerService().initCanItem(item));
                   if (flag){
                       return super.updateById(canItem);
                   }
               }
           }
        }
        return false;
    }

    //删除数据，同时删除外包数据库
    public boolean removeByIdWithOuter(Serializable id) {
        if (outerService() != null){
           boolean flag = outerService().removeById(id);
           if (flag){
               return super.removeById(id);
           }else {
               //查询是否已经删除
               QueryWrapper<T> queryWrapper2 = new QueryWrapper<>();
               queryWrapper2.select(idTableFieldName);
               queryWrapper2.eq(idTableFieldName,id);
               T t = (T) outerService().getOne(queryWrapper2);
               if (t == null){
                   return super.removeById(id);
               }
           }
        }
        return false;
    }


    @Override
    public void query(T item) {
        this.canItem = (T) initCanItem(item);
        outerService().query(item);
    }

    //开始同步数据
    @Override
    public void startSync() {
        try {
            initCanItem(null);

            //获取本地最后更新值
            //获取最后的的值，默认最后的值是最大值
            QueryWrapper<T> queryWrapper = new QueryWrapper<>();
            queryWrapper.orderByDesc(syncFieldName);
            queryWrapper.last("limit 0,1");
            queryWrapper.select(syncFieldName);
            Map a = getMap(queryWrapper);

            //查找外包数据库
            if (outerService() != null){
                Object listObj = null;
                if (a != null){
                    listObj = a.get(syncFieldName);
                }
                int size = 0;
                do {
                    size = 0;
                    QueryWrapper<T> queryWrapper2 = new QueryWrapper<>();
                    queryWrapper2.select(outerService().getSelectColunm());
                    queryWrapper2.isNull(syncFieldName);
                    queryWrapper2.orderByAsc(syncFieldName);
                    if (listObj != null){
                        queryWrapper2.ge(syncFieldName,listObj);
                    }
                    Page<T> page = new Page<>(0,200);
                    IPage<T> iPage = outerService().page(page,queryWrapper2);
                    size = iPage.getRecords().size();

                    for (int i = 0;i < iPage.getRecords().size();i++){
                        T can = initCanItem(iPage.getRecords().get(i),dsFieldList);
                        if (can == null){
                            size = -1;
                            break;
                        }
                        boolean flag =  save(can);
                        //保存失败，就退出
                        if (!flag){
                            size = -1;
                            break;
                        }
                    }
                }while (size < 200);
            }
        }catch (Exception e){
            log.error(getTClass().getName()+"同步数据失败",e);
        }
    }

    //获取当前能够操作的属性，从新设置model,同时整理能够操作的属性
    public T initCanItem(T item,List<Field> fieldList){
        try {
            T newItem = null;
            for (int i = 0;i < fieldList.size();i++){
                Field field = fieldList.get(i);
                if (field.get(item) != null){
                    if (newItem == null){
                        newItem = getTClass().newInstance();
                    }
                    field.set(newItem,field.get(item));
                }
            }
            return newItem;
        }catch (Exception e){
            log.error("SyncServiceImpl.initCanItem 同步数据是吧",e);
        }
       return null;
    }


    //获取当前能够操作的属性，从新设置model,同时整理能够操作的属性
    public T initCanItem(T item)  {
        dsFieldList = new ArrayList<>();
        selectColunmList = new ArrayList<>();
        idTableFieldName = "";
        dsFieldOnlyList = new ArrayList<>();

        Class cls = getTClass();
        Field[] fieldList = cls.getDeclaredFields();
        try {
            T newItem = null;
            for (int i = 0;i < fieldList.length;i++){
                Field field = fieldList[i];
                if (Modifier.isFinal(field.getModifiers())){
                    continue;
                }
                TableField tableField = field.getAnnotation(TableField.class);
                if (tableField != null && tableField.exist() == false) {
                    continue;
                }

                String tableFieldName = "";
                if (tableField != null && tableField.value() != null){
                    tableFieldName = tableField.value();
                }else {
                    tableFieldName = camelToUnderline(field.getName());
                }

                //判断是否同一个数据库
                DSTableField dsTableField = field.getAnnotation(DSTableField.class);
                if (dsTableField != null && !StringUtils.isEmpty(getDSName()) && !dsTableField.value().equals(getDSName())){
                    continue;
                }

                if (dsTableField != null && dsTableField.isSync()){
                    syncField = field;
                    syncFieldName = tableFieldName;
                }

                //只属于当前的
                if (dsTableField != null && dsTableField.value().equals(getDSName())){
                    dsFieldOnlyList.add(field);
                }
                selectColunmList.add(tableFieldName);
                dsFieldList.add(field);

                try {
                    field.setAccessible(true);
                    if (item != null && field.get(item) != null){
                        if (newItem == null){
                            newItem = (T) cls.newInstance();
                        }
                        field.set(newItem,field.get(item));
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }

                TableId tableId = field.getAnnotation(TableId.class);
                if (tableId != null){
                    if (tableId.value() == null){
                        throw new RuntimeException(cls.getName()+" 类 需要提供 @TableId 字段的value值 ");
                    }else {
                        idFile = field;
                        idTableFieldName = tableFieldName;
                    }
                }
            }
            if (idFile == null){
                throw new RuntimeException(cls.getName()+" 类 需要提供 @TableId 注释 ");
            }
            if (syncField == null){
                throw new RuntimeException(cls.getName()+" 类 无法获取到用于同步的字段，请配置 @DSSysncField ");
            }
            return newItem;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    //获取相关的数据库操作源，子类需要重新
    public Sync1ServiceImpl outerService() {
        return null;
    }

    /**
     * 将驼峰命名转化成下划线
     * @param para
     * @return
     */
    public static String camelToUnderline(String para){
        if(para.length()<3){
            return para.toLowerCase();
        }
        StringBuilder sb=new StringBuilder(para);
        int temp=0;//定位
        //从第三个字符开始 避免命名不规范
        for(int i=2;i<para.length();i++){
            if(Character.isUpperCase(para.charAt(i))){
                sb.insert(i+temp, "_");
                temp+=1;
            }
        }
        return sb.toString().toLowerCase();
    }


    //当前操作的数据库原
    public String getDSName(){
        Class cls = getClass();
        DS ds = (DS) cls.getAnnotation(DS.class);
        if (ds != null){
            return ds.value();
        }
        return null;
    }


    public Class<T> getTClass()
    {
        Class<?> cls = getClass();
        Type type = cls.getGenericSuperclass();
        cls = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        return (Class<T>)cls;
    }

    public String getSelectColunm() {
        String  text = "";
        for (int i = 0;i < selectColunmList.size();i++){
            if (i == 0){
                text = selectColunmList.get(i);
            }else {
                text = text+","+selectColunmList.get(i);
            }
        }
        return text;
    }

    public List<Field> getDsFieldList() {
        return dsFieldList;
    }

    public List<String> getSelectColunmList() {
        return selectColunmList;
    }

    public Field getIdFile() {
        return idFile;
    }

    public String getIdTableFieldName() {
        return idTableFieldName;
    }

    public List<Field> getDsFieldOnlyList() {
        return dsFieldOnlyList;
    }


}
